import L from "leaflet";

L.WindFeatherLayer = L.Layer.extend({
  includes: L.Mixin.Events,

  options: {
    windDataUV: [],
    zIndex: 20, //图层index
    scale: 0.22,
    startLon: 0,
    endLon: 360,
    startLat: 90,
    endLat: -90,
  },

  SetData: function (windDataUV) {
    let self = this;
    self.options.windDataUV = windDataUV;
    self._reset();
  },
  _reset: function () {
    let container = this._container;
    let canvas = this._canvas;
    let size = this._map.getSize();
    let lt = this._map.containerPointToLayerPoint([0, 0]);

    L.DomUtil.setPosition(container, lt);

    container.style.width = size.x + "px";
    container.style.height = size.y + "px";

    canvas.width = size.x;
    canvas.height = size.y;
    canvas.style.width = size.x + "px";
    canvas.style.height = size.y + "px";

    this._draw(true);
  },
  _draw: function () {
    let self = this,
      canvas = this._canvas,
      map = this._map;
    if (self.options.windDataUV.length <= 0) {
      return;
    }
    let startLon = self.options.startLon;
    let startLat = self.options.startLat;
    let endLon = self.options.endLon;
    let endLat = self.options.endLat;

    if (L.Browser.canvas && map) {
      let ctx = canvas.getContext("2d");
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      self.id = self._makeid();
      let id = self.id;
      this.currentzoom = map.getZoom();
      this.currentbounds = map.getBounds();
      this.leftup = this.currentbounds.getNorthWest();
      this.rightdown = this.currentbounds.getSouthEast();
      this.range = this._getRange(
        this.leftup,
        this.rightdown,
        this.currentzoom
      );

      let dataCell = (startLat - endLat) / self.options.windDataUV.length;
      let z = self.currentzoom,
        zr = Math.pow(2, z);
      for (let i = this.range.up; i <= this.range.down; i++) {
        for (let j = this.range.left; j <= this.range.right; j++) {
          let zheng = Math.floor(j / zr);
          let yu = j % zr;
          if (yu < 0) {
            yu = yu + zr;
          }
          let row = i;
          let col = yu;
          let cellInterval = (2 * Math.PI) / (256 * Math.pow(2, z));
          let firstX = col * cellInterval * 256 - Math.PI + cellInterval / 2;
          let firstY = Math.PI - row * cellInterval * 256 - cellInterval / 2;
          let interval = 64;
          for (let h = 0; h < 256 / interval; h++) {
            for (let w = 0; w < 256 / interval; w++) {
              let lonlat = self._getLonlat(
                firstX,
                firstY,
                cellInterval,
                w * interval,
                h * interval
              );
              let lon = lonlat.lon;
              let lat = lonlat.lat;
              let querylng = lon;
              querylng = querylng % 360;
              if (querylng < 0) {
                querylng = querylng + 360;
              }
              if (
                lat > startLat &&
                lat < endLat &&
                querylng < startLon &&
                querylng > endLon
              ) {
                continue;
              }
              if (
                !self.options.windDataUV[
                  Math.floor((startLat - lat) / dataCell)
                ]
              ) {
                continue;
              }
              if (
                !self.options.windDataUV[
                  Math.floor((startLat - lat) / dataCell)
                ][Math.floor((querylng - startLon) / dataCell)]
              ) {
                continue;
              }
              let uv =
                self.options.windDataUV[
                  Math.floor((startLat - lat) / dataCell)
                ][Math.floor((querylng - startLon) / dataCell)];
              if (!uv) {
                continue;
              }
              let u = uv.u,
                v = uv.v;
              if (u === 0 && v === 0) {
                continue;
              }
              lon = lonlat.lon + 360 * zheng;
              let screenpoint = map.latLngToContainerPoint(L.latLng(lat, lon));

              let uvInfo = self._computeUV(u, v);
              let value = uvInfo.value;
              let angle = uvInfo.angle;
              let level = self._chooseWindLevel(value);
              let color = self._setcolor(value);
              color.a = 1;
              self._drawIcon(
                ctx,
                screenpoint.x,
                screenpoint.y,
                self.options.scale,
                angle,
                color,
                level,
                id
              );
            }
          }
        }
      }
    }
  },
  _drawIcon: function (context, x, y, scale, angle, color, windlevel, id) {
    let self = this;
    let image = new Image();
    // image.src = require(`./wind/${windlevel}.png`);

    if (self.options.FeatherMode == "Feather") {
      image.src = new URL(`./wind/${windlevel}.png`, import.meta.url).href;
    } else {
      image.src = new URL(`./wind/wind-mark.png`, import.meta.url).href;
    }

    image.onload = function () {
      if (id !== self.id) {
        return;
      }
      context.save();
      let w = image.width * scale;
      let h = image.height * scale;
      context.translate(x + w / 2, y + h / 2);
      context.rotate((angle * Math.PI) / 180);
      context.drawImage(image, -(w / 2), -(h / 2), w, h);
      let li = Math.sqrt(w * w + h * h); //斜边
      context.restore();
      let dataL = context.getImageData(
        x + w / 2 - li / 2,
        y + h / 2 - li / 2,
        li,
        li
      );
      for (let i = 0; i < dataL.data.length; i += 4) {
        //逐像素修改颜色透明度
        if (
          dataL.data[i] === 0 &&
          dataL.data[i + 1] === 0 &&
          dataL.data[i + 2] === 0 &&
          dataL.data[i + 3] === 0
        ) {
          continue;
        }
        dataL.data[i] = color.r + dataL.data[i] - 255;
        dataL.data[i + 1] = color.g + dataL.data[i + 1] - 255;
        dataL.data[i + 2] = color.b + dataL.data[i + 2];
        dataL.data[i + 3] = dataL.data[i + 3]; //体现阴影效果
      }
      context.putImageData(dataL, x + w / 2 - li / 2, y + h / 2 - li / 2);
    };
  },
  _clearCanvas: function () {
    let canvas = this._canvas;
    try {
      let ctx = canvas.getContext("2d");
      ctx.clearRect(0, 0, canvas.width, canvas.height);
    } catch (e) {}
  },

  /*------------------------------------ 外置函数 ------------------------------------------*/

  setzIndex: function (zIndex) {
    this._container.style.zIndex = zIndex;
  },

  /*------------------------------------ 事件 ------------------------------------------*/

  initialize: function (options) {
    L.setOptions(this, options);
    this.currentbounds = null;
    this.currentzoom = null;
  },
  onAdd: function (map) {
    this._map = map;
    if (!this._container) {
      this._initCanvas();
    }
    map._panes.overlayPane.appendChild(this._container);
    map.on("zoomstart", this._clearCanvas, this);
    map.on("moveend", this._reset, this);
    if (map.options.zoomAnimation && L.Browser.any3d) {
      map.on("zoomanim", this._animateZoom, this);
    }
    this._reset();
  },
  onRemove: function (map) {
    map.getPanes().overlayPane.removeChild(this._container);
    map.off("zoomstart", this._clearCanvas, this);
    map.off("moveend", this._reset, this);
    if (map.options.zoomAnimation) {
      map.off("zoomanim", this._animateZoom, this);
    }
  },
  addTo: function (map) {
    map.addLayer(this);
    return this;
  },
  bringToBack: function () {
    let pane = this._map._panes.overlayPane;
    if (this._canvas) {
      pane.insertBefore(this._canvas, pane.firstChild);
    }
    return this;
  },
  _initCanvas: function () {
    this._container = L.DomUtil.create("div", "leaflet-image-layer");
    this._canvas = L.DomUtil.create("canvas", "");
    this._canvas.style.pointerEvents = "none";
    this.setzIndex(this.options.zIndex);

    if (this._map.options.zoomAnimation && L.Browser.any3d) {
      L.DomUtil.addClass(this._canvas, "leaflet-zoom-animated");
    } else {
      L.DomUtil.addClass(this._canvas, "leaflet-zoom-hide");
    }

    this._container.appendChild(this._canvas);

    L.extend(this._canvas, {
      onselectstart: L.Util.falseFn,
      onmousemove: L.Util.falseFn,
      onload: L.bind(this._onCanvasLoad, this),
    });
  },
  _animateZoom: function (e) {
    let map = this._map,
      container = this._container,
      canvas = this._canvas,
      scale = map.getZoomScale(e.zoom),
      nw = map.containerPointToLatLng([0, 0]),
      se = map.containerPointToLatLng([canvas.width, canvas.height]),
      topLeft = map._latLngToNewLayerPoint(nw, e.zoom, e.center),
      size = map
        ._latLngToNewLayerPoint(se, e.zoom, e.center)
        ._subtract(topLeft),
      origin = topLeft._add(size._multiplyBy((1 / 2) * (1 - 1 / scale)));
  },
  _onCanvasLoad: function () {
    this.fire("load");
  },

  /*------------------------------------ 工具函数 ------------------------------------------*/

  /**角度修正 */
  _correctAngle: function (angle) {
    angle = (angle / Math.PI) * 180.0 + 90;
    if (angle < 0) {
      angle = angle + 360;
    }
    angle = 360 - angle;
    return angle;
  },
  /**风力选择 */
  _chooseWindLevel: function (speed) {
    let level;
    if (speed >= 0 && speed <= 2) {
      level = 1;
    } else if (speed > 2 && speed <= 4) {
      level = 2;
    } else if (speed > 4 && speed <= 6) {
      level = 3;
    } else if (speed > 6 && speed <= 8) {
      level = 4;
    } else if (speed > 8 && speed <= 10) {
      level = 5;
    } else if (speed > 10 && speed <= 12) {
      level = 6;
    } else if (speed > 12 && speed <= 14) {
      level = 7;
    } else if (speed > 14 && speed <= 16) {
      level = 8;
    } else if (speed > 16 && speed <= 18) {
      level = 9;
    } else if (speed > 18 && speed <= 20) {
      level = 10;
    } else if (speed > 20 && speed <= 24) {
      level = 11;
    } else if (speed > 24 && speed <= 28) {
      level = 12;
    } else if (speed > 28 && speed <= 32) {
      level = 13;
    } else if (speed > 32 && speed <= 36) {
      level = 14;
    } else if (speed > 36 && speed <= 40) {
      level = 15;
    } else {
      level = 15;
    }
    return level;
  },
  /**生成随机字符串 */
  _makeid: function () {
    let text = "";
    let possible =
      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    for (let i = 0; i < 5; i++) {
      text += possible.charAt(Math.floor(Math.random() * possible.length));
    }
    return text;
  },
  /**计算切片角点的坐标 */
  _getLonlat: function (x, y, cell, xAdd, yAdd) {
    let lon = ((x + xAdd * cell) / Math.PI) * 180; //第一个点 左上
    let lat =
      (180 / Math.PI) *
      (2 *
        Math.atan(
          Math.exp((((y - yAdd * cell) / Math.PI) * 180 * Math.PI) / 180)
        ) -
        Math.PI / 2);
    return {
      lon: lon,
      lat: lat,
    };
  },
  /**uv计算角度和大小 */
  _computeUV: function (u_value, v_value) {
    let value = Math.sqrt(u_value * u_value + v_value * v_value);
    let angle = Math.acos(u_value / value);
    if (v_value < 0) {
      angle = -angle;
    }
    angle = Math.round((angle / Math.PI) * 180.0 + 90);
    if (angle < 0) {
      angle = angle + 360;
    }
    angle = Math.round(360 - angle);
    return {
      value: value,
      angle: angle,
    };
  },
  /**线性变化颜色带 */
  _setcolor: function (speed) {
    let minValue = 0,
      maxValue = 18;
    let col, r, g, b;
    let part = (maxValue - minValue) / 4.0;
    let colorRamp = 255.0 / part;
    if (speed < part + minValue) {
      col = speed - minValue;
      r = 0;
      g = Math.round(col * colorRamp);
      b = 255;
    } else if (speed >= part + minValue && speed < 2 * part + minValue) {
      col = speed - (part + minValue);
      r = 0;
      g = 255;
      b = Math.round(255 - col * colorRamp);
    } else if (speed >= 2 * part + minValue && speed < 3 * part + minValue) {
      col = speed - (2 * part + minValue);
      r = Math.round(col * colorRamp);
      g = 255;
      b = 0;
    } else if (speed >= 3 * part + minValue && speed < 4 * part + minValue) {
      col = speed - (3 * part + minValue);
      r = 255;
      g = Math.round(255 - col * colorRamp);
      b = 0;
    } else {
      r = 255;
      g = 0;
      b = 0;
    }
    return { r: r, g: g, b: b };
  },
  /**根据经纬度计算行列号 */
  _getRange: function (leftup, rightdown, zoom) {
    let leftuprowcol = this._getCornerNum(leftup.lat, leftup.lng, zoom);
    let rightdownrowcol = this._getCornerNum(
      rightdown.lat,
      rightdown.lng,
      zoom
    );
    return {
      left:
        leftuprowcol.colNum === 0
          ? leftuprowcol.colNum
          : leftuprowcol.colNum - 1,
      up:
        leftuprowcol.rowNum === 0
          ? leftuprowcol.rowNum
          : leftuprowcol.rowNum - 1,
      right: rightdownrowcol.colNum,
      down: rightdownrowcol.rowNum,
    };
  },
  /**计算横轴墨卡托投影下的坐标 */
  _getCornerNum: function (lat, lon, level) {
    let d = Math.PI / 180;
    let x = lon * d;
    let y = Math.log(Math.tan(((90 + lat) * Math.PI) / 360)) / (Math.PI / 180);
    y = (y * Math.PI) / 180;
    //先转墨卡托，用墨卡托求行列号
    let rowNumber = ((Math.PI - y) / (2 * Math.PI)) * Math.pow(2, level);
    let colNumber = ((x + Math.PI) / (2 * Math.PI)) * Math.pow(2, level);
    return {
      rowNum: Math.round(rowNumber),
      colNum: Math.round(colNumber),
    };
  },
});

export default function (options) {
  return new L.WindFeatherLayer(options);
}
